/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.urbanski.ksp.kspmultitool.ui;

import com.urbanski.ksp.kspmultitool.util.Constants;
import com.urbanski.ksp.kspmultitool.util.Utils;
import com.urbanski.ksp.kspmultitool.vo.Body;
import com.urbanski.ksp.kspmultitool.vo.Function;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.KeyEvent;
import java.io.File;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.EmptyStackException;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;
import java.util.TreeMap;
import javax.swing.BoxLayout;
import javax.swing.JButton;
import javax.swing.JFileChooser;
import javax.swing.JPanel;
import javax.swing.SwingConstants;

/**
 *
 * @author murbanski004
 */
public class Main extends javax.swing.JFrame
{
    public static Main instance;
    public Map<String, Body> bodies;
    public Body kerbol;
    public List<String> commandHistory = new ArrayList<>();
    public Map<String, Double> bodyVariables = new LinkedHashMap<>();
    public Map<String, Double> userVariables = new TreeMap<>();
    public int currentCommand = 0;

    /**
     * Creates new form Main
     */
    public Main() throws Exception
    {
        instance = this;
        bodies = Utils.readBodiesFile("bodies.csv");
        initComponents();

        for (Body b : bodies.values())
            bodyComboBox.addItem(b);

        kerbol = bodies.get("Kerbol");

        bodyComboBox.setSelectedItem(bodies.get("Kerbin"));

        setLocationRelativeTo(null);

        userVariables.put("G", Constants.G);
        userVariables.put("pi", Math.PI);
        userVariables.put("e", Math.E);
        userVariables.put("c", 299792458d);

        functionsPanel.setLayout(new BoxLayout(functionsPanel, BoxLayout.Y_AXIS));
        userVariablesPanel.setLayout(new BoxLayout(userVariablesPanel, BoxLayout.Y_AXIS));
        bodyVariablesPanel.setLayout(new BoxLayout(bodyVariablesPanel, BoxLayout.Y_AXIS));

        makeFunctionsButtons();
        makeVariableButtons(bodyVariablesPanel, bodyVariables);
        makeVariableButtons(userVariablesPanel, userVariables);
        
        calculateButton.setVisible(false);
    }

    public void makeFunctionsButtons()
    {
        functionsPanel.removeAll();

        for (final Function f : Constants.FUNCTIONS)
        {
            JButton button = new JButton(f.tooltipText);
            button.setFont(new Font("Monospaced", Font.PLAIN, 11));
            button.setPreferredSize(new Dimension(200, button.getPreferredSize().height));
            button.setMinimumSize(button.getPreferredSize());
            button.setMaximumSize(button.getPreferredSize());
            button.setHorizontalAlignment(SwingConstants.LEFT);
            button.setToolTipText(f.tooltipText);

            button.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    inputField.setText(inputField.getText() + f.name + '(');
                    inputField.setCaretPosition(inputField.getText().length());
                    inputField.requestFocusInWindow();
                }
            });

            functionsPanel.add(button);
        }

        functionsPanel.validate();
    }

    public void makeVariableButtons(JPanel panel, Map<String, Double> variables)
    {
        panel.removeAll();

        for (final String var : variables.keySet())
        {
            double val = variables.get(var);
            JButton button = new JButton(var + " = " + val);
            button.setFont(new Font("Monospaced", Font.PLAIN, 11));
            button.setPreferredSize(new Dimension(200, button.getPreferredSize().height));
            button.setMinimumSize(button.getPreferredSize());
            button.setMaximumSize(button.getPreferredSize());
            button.setHorizontalAlignment(SwingConstants.LEFT);
            button.setToolTipText(Double.toString(val));

            button.addActionListener(new ActionListener()
            {
                @Override
                public void actionPerformed(ActionEvent e)
                {
                    inputField.setText(inputField.getText() + var);
                    inputField.setCaretPosition(inputField.getText().length());
                    inputField.requestFocusInWindow();
                }
            });

            panel.add(button);
        }

        panel.validate();
    }

    /**
     * This method is called from within the constructor to initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is always
     * regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents()
    {

        periapsisUnits = new javax.swing.ButtonGroup();
        apoapsisUnits = new javax.swing.ButtonGroup();
        jTabbedPane1 = new javax.swing.JTabbedPane();
        jPanel1 = new javax.swing.JPanel();
        jLabel1 = new javax.swing.JLabel();
        jLabel2 = new javax.swing.JLabel();
        periapsisField = new javax.swing.JTextField();
        apoapsisField = new javax.swing.JTextField();
        circularCheckbox = new javax.swing.JCheckBox();
        pmCheckbox = new javax.swing.JRadioButton();
        pkmCheckbox = new javax.swing.JRadioButton();
        pMmCheckbox = new javax.swing.JRadioButton();
        pGmCheckbox = new javax.swing.JRadioButton();
        amCheckbox = new javax.swing.JRadioButton();
        akmCheckbox = new javax.swing.JRadioButton();
        aMmCheckbox = new javax.swing.JRadioButton();
        aGmCheckbox = new javax.swing.JRadioButton();
        jLabel3 = new javax.swing.JLabel();
        bodyComboBox = new javax.swing.JComboBox();
        jLabel4 = new javax.swing.JLabel();
        jLabel5 = new javax.swing.JLabel();
        jLabel6 = new javax.swing.JLabel();
        jLabel7 = new javax.swing.JLabel();
        jLabel11 = new javax.swing.JLabel();
        jLabel13 = new javax.swing.JLabel();
        jLabel14 = new javax.swing.JLabel();
        jLabel15 = new javax.swing.JLabel();
        jLabel16 = new javax.swing.JLabel();
        jLabel17 = new javax.swing.JLabel();
        jLabel18 = new javax.swing.JLabel();
        jLabel19 = new javax.swing.JLabel();
        jLabel20 = new javax.swing.JLabel();
        jLabel21 = new javax.swing.JLabel();
        jLabel22 = new javax.swing.JLabel();
        jLabel23 = new javax.swing.JLabel();
        jLabel24 = new javax.swing.JLabel();
        jLabel25 = new javax.swing.JLabel();
        jLabel8 = new javax.swing.JLabel();
        smaBodyLabel = new javax.swing.JLabel();
        rpBodyLabel = new javax.swing.JLabel();
        raBodyLabel = new javax.swing.JLabel();
        TBodyLabel = new javax.swing.JLabel();
        TKSPBodyLabel = new javax.swing.JLabel();
        eBodyLabel = new javax.swing.JLabel();
        incBodyLabel = new javax.swing.JLabel();
        MBodyLabel = new javax.swing.JLabel();
        gBodyLabel = new javax.swing.JLabel();
        muBodyLabel = new javax.swing.JLabel();
        rBodyLabel = new javax.swing.JLabel();
        maxElevationBodyLabel = new javax.swing.JLabel();
        soiBodyLabel = new javax.swing.JLabel();
        flyingLowBodyLabel = new javax.swing.JLabel();
        flyingHighBodyLabel = new javax.swing.JLabel();
        nearSpaceBodyLabel = new javax.swing.JLabel();
        outerSpaceBodyLabel = new javax.swing.JLabel();
        fillerLabel = new javax.swing.JLabel();
        jLabel9 = new javax.swing.JLabel();
        inclinationField = new javax.swing.JTextField();
        calculateButton = new javax.swing.JButton();
        jLabel10 = new javax.swing.JLabel();
        smaCraftLabel = new javax.swing.JLabel();
        jLabel12 = new javax.swing.JLabel();
        TCraftLabel = new javax.swing.JLabel();
        jLabel26 = new javax.swing.JLabel();
        TKSPCraftLabel = new javax.swing.JLabel();
        jLabel27 = new javax.swing.JLabel();
        eCraftLabel = new javax.swing.JLabel();
        jLabel28 = new javax.swing.JLabel();
        darknessCraftLabel = new javax.swing.JLabel();
        jLabel29 = new javax.swing.JLabel();
        jLabel30 = new javax.swing.JLabel();
        vpCraftLabel = new javax.swing.JLabel();
        vaCraftLabel = new javax.swing.JLabel();
        errorLabel = new javax.swing.JLabel();
        jPanel3 = new javax.swing.JPanel();
        jScrollPane1 = new javax.swing.JScrollPane();
        outputPane = new javax.swing.JTextArea();
        jScrollPane2 = new javax.swing.JScrollPane();
        functionsPanel = new javax.swing.JPanel();
        inputField = new javax.swing.JTextField();
        importButton = new javax.swing.JButton();
        exportButton = new javax.swing.JButton();
        jScrollPane = new javax.swing.JScrollPane();
        userVariablesPanel = new javax.swing.JPanel();
        jScrollPane4 = new javax.swing.JScrollPane();
        bodyVariablesPanel = new javax.swing.JPanel();
        jPanel2 = new javax.swing.JPanel();

        setDefaultCloseOperation(javax.swing.WindowConstants.EXIT_ON_CLOSE);
        setTitle("KSP Multitool");
        addWindowListener(new java.awt.event.WindowAdapter()
        {
            public void windowClosing(java.awt.event.WindowEvent evt)
            {
                formWindowClosing(evt);
            }
        });

        jLabel1.setText("Periapsis:");

        jLabel2.setText("Apoapsis:");

        periapsisField.addKeyListener(new java.awt.event.KeyAdapter()
        {
            public void keyReleased(java.awt.event.KeyEvent evt)
            {
                periapsisFieldKeyReleased(evt);
            }
        });

        apoapsisField.addKeyListener(new java.awt.event.KeyAdapter()
        {
            public void keyReleased(java.awt.event.KeyEvent evt)
            {
                apoapsisFieldKeyReleased(evt);
            }
        });

        circularCheckbox.setText("Circular");
        circularCheckbox.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                circularCheckboxActionPerformed(evt);
            }
        });

        periapsisUnits.add(pmCheckbox);
        pmCheckbox.setText("m");
        pmCheckbox.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                pmCheckboxActionPerformed(evt);
            }
        });

        periapsisUnits.add(pkmCheckbox);
        pkmCheckbox.setSelected(true);
        pkmCheckbox.setText("km");
        pkmCheckbox.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                pmCheckboxActionPerformed(evt);
            }
        });

        periapsisUnits.add(pMmCheckbox);
        pMmCheckbox.setText("Mm");
        pMmCheckbox.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                pmCheckboxActionPerformed(evt);
            }
        });

        periapsisUnits.add(pGmCheckbox);
        pGmCheckbox.setText("Gm");
        pGmCheckbox.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                pmCheckboxActionPerformed(evt);
            }
        });

        apoapsisUnits.add(amCheckbox);
        amCheckbox.setText("m");
        amCheckbox.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                pmCheckboxActionPerformed(evt);
            }
        });

        apoapsisUnits.add(akmCheckbox);
        akmCheckbox.setSelected(true);
        akmCheckbox.setText("km");
        akmCheckbox.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                pmCheckboxActionPerformed(evt);
            }
        });

        apoapsisUnits.add(aMmCheckbox);
        aMmCheckbox.setText("Mm");
        aMmCheckbox.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                pmCheckboxActionPerformed(evt);
            }
        });

        apoapsisUnits.add(aGmCheckbox);
        aGmCheckbox.setText("Gm");
        aGmCheckbox.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                pmCheckboxActionPerformed(evt);
            }
        });

        jLabel3.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        jLabel3.setText("Body:");

        bodyComboBox.addItemListener(new java.awt.event.ItemListener()
        {
            public void itemStateChanged(java.awt.event.ItemEvent evt)
            {
                bodyComboBoxItemStateChanged(evt);
            }
        });

        jLabel4.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        jLabel4.setText("Body Info:");

        jLabel5.setText("Semi-major axis:");

        jLabel6.setText("Periapsis:");

        jLabel7.setText("Apoapsis:");

        jLabel11.setText("Orbital period:");

        jLabel13.setText("Eccentricity:");

        jLabel14.setText("Inclination:");

        jLabel15.setText("Mass:");

        jLabel16.setText("Surface gravity:");

        jLabel17.setText("Gravitational parameter:");

        jLabel18.setText("Radius:");

        jLabel19.setText("Max elevation:");

        jLabel20.setText("Sphere of Influence:");

        jLabel21.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
        jLabel21.setText("Science altitudes:");

        jLabel22.setText("Flying low:");

        jLabel23.setText("Flying high:");

        jLabel24.setText("Near space:");

        jLabel25.setText("Outer space:");

        jLabel8.setText("Orbital period (KSP time):");

        smaBodyLabel.setText(" ");

        rpBodyLabel.setText(" ");

        raBodyLabel.setText(" ");

        TBodyLabel.setText(" ");

        TKSPBodyLabel.setText(" ");

        eBodyLabel.setText(" ");

        incBodyLabel.setText(" ");

        MBodyLabel.setText(" ");

        gBodyLabel.setText(" ");

        muBodyLabel.setText(" ");

        rBodyLabel.setText(" ");

        maxElevationBodyLabel.setText(" ");

        soiBodyLabel.setText(" ");

        flyingLowBodyLabel.setText(" ");

        flyingHighBodyLabel.setText(" ");

        nearSpaceBodyLabel.setText(" ");

        outerSpaceBodyLabel.setText(" ");

        fillerLabel.setText(" ");

        jLabel9.setText("Inclination:");

        calculateButton.setText("Calculate");
        calculateButton.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                calculateButtonActionPerformed(evt);
            }
        });

        jLabel10.setText("Semi-major axis:");

        smaCraftLabel.setText(" ");

        jLabel12.setText("Orbital period:");

        TCraftLabel.setText(" ");

        jLabel26.setText("Orbital period (KSP time):");

        TKSPCraftLabel.setText(" ");

        jLabel27.setText("Eccentricity:");

        eCraftLabel.setText(" ");

        jLabel28.setText("Length of darkness:");

        darknessCraftLabel.setText(" ");

        jLabel29.setText("Periapsis orbital velocity:");

        jLabel30.setText("Apoapsis orbital velocity:");

        vpCraftLabel.setText(" ");

        vaCraftLabel.setText(" ");

        errorLabel.setForeground(new java.awt.Color(255, 0, 0));
        errorLabel.setText(" ");

        javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
        jPanel1.setLayout(jPanel1Layout);
        jPanel1Layout.setHorizontalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                        .addComponent(calculateButton, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                        .addGroup(javax.swing.GroupLayout.Alignment.LEADING, jPanel1Layout.createSequentialGroup()
                            .addComponent(jLabel9, javax.swing.GroupLayout.PREFERRED_SIZE, 69, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                            .addComponent(inclinationField, javax.swing.GroupLayout.PREFERRED_SIZE, 93, javax.swing.GroupLayout.PREFERRED_SIZE)))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                            .addComponent(jLabel30, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(jLabel29, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(jLabel28, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(jLabel27, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(jLabel26, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 148, Short.MAX_VALUE)
                            .addComponent(jLabel12, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(jLabel10, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(TCraftLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(smaCraftLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(TKSPCraftLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(eCraftLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(darknessCraftLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(vpCraftLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(vaCraftLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGap(4, 4, 4)
                        .addComponent(circularCheckbox)
                        .addGap(111, 111, 111)
                        .addComponent(errorLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addComponent(jLabel2, javax.swing.GroupLayout.PREFERRED_SIZE, 69, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(apoapsisField, javax.swing.GroupLayout.PREFERRED_SIZE, 93, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                .addComponent(amCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 41, javax.swing.GroupLayout.PREFERRED_SIZE))
                            .addGroup(jPanel1Layout.createSequentialGroup()
                                .addComponent(jLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 69, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                                .addComponent(periapsisField, javax.swing.GroupLayout.PREFERRED_SIZE, 93, javax.swing.GroupLayout.PREFERRED_SIZE)
                                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
                                .addComponent(pmCheckbox, javax.swing.GroupLayout.PREFERRED_SIZE, 41, javax.swing.GroupLayout.PREFERRED_SIZE)))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addComponent(pkmCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(akmCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                            .addComponent(pMmCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                            .addComponent(aMmCheckbox, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(aGmCheckbox)
                            .addComponent(pGmCheckbox, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, 45, javax.swing.GroupLayout.PREFERRED_SIZE))))
                .addGap(20, 20, 20)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addComponent(jLabel3, javax.swing.GroupLayout.PREFERRED_SIZE, 43, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(bodyComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 164, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(jLabel4, javax.swing.GroupLayout.PREFERRED_SIZE, 177, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addGroup(jPanel1Layout.createSequentialGroup()
                        .addGap(10, 10, 10)
                        .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                            .addComponent(jLabel24, javax.swing.GroupLayout.PREFERRED_SIZE, 167, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jLabel23, javax.swing.GroupLayout.PREFERRED_SIZE, 167, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addComponent(jLabel22, javax.swing.GroupLayout.PREFERRED_SIZE, 167, javax.swing.GroupLayout.PREFERRED_SIZE)
                            .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                                .addComponent(jLabel5, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel6, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel7, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel11, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel8, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel13, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel14, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel15, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel16, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel17, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel18, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel19, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                                .addComponent(jLabel20, javax.swing.GroupLayout.PREFERRED_SIZE, 167, javax.swing.GroupLayout.PREFERRED_SIZE))
                            .addComponent(jLabel25, javax.swing.GroupLayout.PREFERRED_SIZE, 167, javax.swing.GroupLayout.PREFERRED_SIZE)))
                    .addComponent(jLabel21, javax.swing.GroupLayout.PREFERRED_SIZE, 177, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(smaBodyLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(rpBodyLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)
                    .addComponent(raBodyLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)
                    .addComponent(TBodyLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)
                    .addComponent(TKSPBodyLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)
                    .addComponent(eBodyLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)
                    .addComponent(incBodyLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)
                    .addComponent(MBodyLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)
                    .addComponent(maxElevationBodyLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)
                    .addComponent(soiBodyLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)
                    .addComponent(rBodyLabel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(gBodyLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(muBodyLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
                    .addComponent(outerSpaceBodyLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)
                    .addComponent(flyingLowBodyLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)
                    .addComponent(flyingHighBodyLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)
                    .addComponent(nearSpaceBodyLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE)
                    .addComponent(fillerLabel, javax.swing.GroupLayout.DEFAULT_SIZE, 415, Short.MAX_VALUE))
                .addContainerGap())
        );
        jPanel1Layout.setVerticalGroup(
            jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel1Layout.createSequentialGroup()
                .addContainerGap()
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel1)
                    .addComponent(periapsisField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(pmCheckbox)
                    .addComponent(pMmCheckbox)
                    .addComponent(pGmCheckbox)
                    .addComponent(jLabel3)
                    .addComponent(bodyComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(pkmCheckbox))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel2)
                    .addComponent(apoapsisField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(amCheckbox)
                    .addComponent(akmCheckbox)
                    .addComponent(aMmCheckbox)
                    .addComponent(aGmCheckbox)
                    .addComponent(jLabel4))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel5)
                    .addComponent(circularCheckbox)
                    .addComponent(smaBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(errorLabel))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel6)
                    .addComponent(rpBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel9)
                    .addComponent(inclinationField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel7)
                    .addComponent(raBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(calculateButton))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel11)
                    .addComponent(TBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(TKSPBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel8)
                    .addComponent(jLabel10)
                    .addComponent(smaCraftLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel13)
                    .addComponent(eBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel12)
                    .addComponent(TCraftLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel14)
                    .addComponent(incBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(TKSPCraftLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel26, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel15)
                    .addComponent(MBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel27)
                    .addComponent(eCraftLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel16)
                    .addComponent(gBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel28)
                    .addComponent(darknessCraftLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel17)
                    .addComponent(muBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel29)
                    .addComponent(vpCraftLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel18)
                    .addComponent(rBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel30)
                    .addComponent(vaCraftLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel19)
                    .addComponent(maxElevationBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel20)
                    .addComponent(soiBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(fillerLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(jLabel21))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel22)
                    .addComponent(flyingLowBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel23)
                    .addComponent(flyingHighBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel24)
                    .addComponent(nearSpaceBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(jLabel25)
                    .addComponent(outerSpaceBodyLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 23, javax.swing.GroupLayout.PREFERRED_SIZE))
                .addGap(12, 12, 12))
        );

        jTabbedPane1.addTab("Orbit/Body Details", jPanel1);

        outputPane.setEditable(false);
        outputPane.setColumns(20);
        outputPane.setFont(new java.awt.Font("Monospaced", 0, 12)); // NOI18N
        outputPane.setRows(5);
        jScrollPane1.setViewportView(outputPane);

        javax.swing.GroupLayout functionsPanelLayout = new javax.swing.GroupLayout(functionsPanel);
        functionsPanel.setLayout(functionsPanelLayout);
        functionsPanelLayout.setHorizontalGroup(
            functionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 279, Short.MAX_VALUE)
        );
        functionsPanelLayout.setVerticalGroup(
            functionsPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 275, Short.MAX_VALUE)
        );

        jScrollPane2.setViewportView(functionsPanel);

        inputField.setFont(new java.awt.Font("Monospaced", 0, 12)); // NOI18N
        inputField.addKeyListener(new java.awt.event.KeyAdapter()
        {
            public void keyPressed(java.awt.event.KeyEvent evt)
            {
                inputFieldKeyPressed(evt);
            }
        });

        importButton.setText("Import...");
        importButton.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                importButtonActionPerformed(evt);
            }
        });

        exportButton.setText("Export...");
        exportButton.addActionListener(new java.awt.event.ActionListener()
        {
            public void actionPerformed(java.awt.event.ActionEvent evt)
            {
                exportButtonActionPerformed(evt);
            }
        });

        javax.swing.GroupLayout userVariablesPanelLayout = new javax.swing.GroupLayout(userVariablesPanel);
        userVariablesPanel.setLayout(userVariablesPanelLayout);
        userVariablesPanelLayout.setHorizontalGroup(
            userVariablesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 279, Short.MAX_VALUE)
        );
        userVariablesPanelLayout.setVerticalGroup(
            userVariablesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 276, Short.MAX_VALUE)
        );

        jScrollPane.setViewportView(userVariablesPanel);

        javax.swing.GroupLayout bodyVariablesPanelLayout = new javax.swing.GroupLayout(bodyVariablesPanel);
        bodyVariablesPanel.setLayout(bodyVariablesPanelLayout);
        bodyVariablesPanelLayout.setHorizontalGroup(
            bodyVariablesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 228, Short.MAX_VALUE)
        );
        bodyVariablesPanelLayout.setVerticalGroup(
            bodyVariablesPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 559, Short.MAX_VALUE)
        );

        jScrollPane4.setViewportView(bodyVariablesPanel);

        javax.swing.GroupLayout jPanel3Layout = new javax.swing.GroupLayout(jPanel3);
        jPanel3.setLayout(jPanel3Layout);
        jPanel3Layout.setHorizontalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel3Layout.createSequentialGroup()
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
                    .addComponent(inputField, javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 572, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
                    .addGroup(jPanel3Layout.createSequentialGroup()
                        .addComponent(importButton, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(exportButton, javax.swing.GroupLayout.PREFERRED_SIZE, 91, javax.swing.GroupLayout.PREFERRED_SIZE))
                    .addComponent(jScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 269, Short.MAX_VALUE)
                    .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addComponent(jScrollPane4))
        );
        jPanel3Layout.setVerticalGroup(
            jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGroup(jPanel3Layout.createSequentialGroup()
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
                    .addComponent(jScrollPane1)
                    .addGroup(jPanel3Layout.createSequentialGroup()
                        .addComponent(jScrollPane2, javax.swing.GroupLayout.PREFERRED_SIZE, 277, javax.swing.GroupLayout.PREFERRED_SIZE)
                        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                        .addComponent(jScrollPane))
                    .addComponent(jScrollPane4))
                .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
                .addGroup(jPanel3Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
                    .addComponent(inputField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
                    .addComponent(importButton)
                    .addComponent(exportButton)))
        );

        jTabbedPane1.addTab("Calculator", jPanel3);

        javax.swing.GroupLayout jPanel2Layout = new javax.swing.GroupLayout(jPanel2);
        jPanel2.setLayout(jPanel2Layout);
        jPanel2Layout.setHorizontalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 1083, Short.MAX_VALUE)
        );
        jPanel2Layout.setVerticalGroup(
            jPanel2Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addGap(0, 591, Short.MAX_VALUE)
        );

        jTabbedPane1.addTab("Preferences", jPanel2);

        javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
        getContentPane().setLayout(layout);
        layout.setHorizontalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jTabbedPane1)
        );
        layout.setVerticalGroup(
            layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
            .addComponent(jTabbedPane1)
        );

        pack();
    }// </editor-fold>//GEN-END:initComponents

    private void bodyComboBoxItemStateChanged(java.awt.event.ItemEvent evt)//GEN-FIRST:event_bodyComboBoxItemStateChanged
    {//GEN-HEADEREND:event_bodyComboBoxItemStateChanged
        if (evt.getStateChange() == ItemEvent.SELECTED)
        {
            setBodyLabels((Body) bodyComboBox.getSelectedItem());
            calculateButtonActionPerformed(null);
        }
    }//GEN-LAST:event_bodyComboBoxItemStateChanged

    private void circularCheckboxActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_circularCheckboxActionPerformed
    {//GEN-HEADEREND:event_circularCheckboxActionPerformed

        boolean b = !circularCheckbox.isSelected();

        apoapsisField.setEnabled(b);
        amCheckbox.setEnabled(b);
        akmCheckbox.setEnabled(b);
        aMmCheckbox.setEnabled(b);
        aGmCheckbox.setEnabled(b);
        
        calculateButtonActionPerformed(null);
    }//GEN-LAST:event_circularCheckboxActionPerformed

    private void formWindowClosing(java.awt.event.WindowEvent evt)//GEN-FIRST:event_formWindowClosing
    {//GEN-HEADEREND:event_formWindowClosing
    }//GEN-LAST:event_formWindowClosing

    private void inputFieldKeyPressed(java.awt.event.KeyEvent evt)//GEN-FIRST:event_inputFieldKeyPressed
    {//GEN-HEADEREND:event_inputFieldKeyPressed

        if (evt.getKeyCode() == KeyEvent.VK_ENTER)
        {
            String text = inputField.getText().trim();
            if (text.isEmpty())
                return;

            commandHistory.add(text);
            outputPane.append(text + "\n");

            try
            {
                outputPane.append("    = " + Utils.computeExpression(text) + "\n");
            }
            catch (IllegalArgumentException e)
            {
                outputPane.append("    " + e.getMessage() + "\n");
            }
            catch (EmptyStackException e)
            {
                outputPane.append("    Unexpected end of line\n");
            }

            inputField.setText("");
            makeVariableButtons(userVariablesPanel, userVariables);
            currentCommand = commandHistory.size();
        }
        else if (evt.getKeyCode() == KeyEvent.VK_UP)
        {
            currentCommand--;
            if (currentCommand == -1)
                currentCommand = commandHistory.size();

            if (currentCommand == commandHistory.size())
                inputField.setText("");
            else
                inputField.setText(commandHistory.get(currentCommand));
        }
        else if (evt.getKeyCode() == KeyEvent.VK_DOWN)
        {
            currentCommand++;
            if (currentCommand > commandHistory.size())
                currentCommand = 0;

            if (currentCommand == commandHistory.size())
                inputField.setText("");
            else
                inputField.setText(commandHistory.get(currentCommand));
        }
    }//GEN-LAST:event_inputFieldKeyPressed

    private void importButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_importButtonActionPerformed
    {//GEN-HEADEREND:event_importButtonActionPerformed
        if (!Utils.showConfirmDialog("Loading defaults will overwrite existing variables with the same names"))
        {
            return;
        }

        JFileChooser jfc = Utils.getLoadFileDialog();
        if (jfc.showOpenDialog(this) == JFileChooser.APPROVE_OPTION)
        {
            File f = jfc.getSelectedFile();
            if (f != null)
            {
                try
                {
                    Scanner in = new Scanner(f);
                    while (in.hasNextLine())
                    {
                        String s = in.nextLine();
                        if (s.isEmpty()) continue;
                        int i = s.indexOf('=');
                        if (i < 0) continue;
                        String var = s.substring(0, i);
                        try
                        {
                            double d = Double.parseDouble(s.substring(i + 1));
                            userVariables.put(var, d);
                        }
                        catch (NumberFormatException e)
                        {
                            Utils.showErrorDialog("Invalid entry in variables file", e);
                        }
                    }
                    in.close();
                }
                catch (Exception ex)
                {
                    Utils.showErrorDialog("Error reading file", ex);
                }
            }
        }

        makeVariableButtons(userVariablesPanel, userVariables);
    }//GEN-LAST:event_importButtonActionPerformed

    private void exportButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_exportButtonActionPerformed
    {//GEN-HEADEREND:event_exportButtonActionPerformed
        File f = Utils.getSaveFile();
        if (f != null)
        {
            try
            {
                PrintWriter out = new PrintWriter(f);
                for (String var : userVariables.keySet())
                    out.println(var + "=" + userVariables.get(var));
                out.close();
            }
            catch (Exception ex)
            {
                Utils.showErrorDialog("Error saving file", ex);
            }
        }
    }//GEN-LAST:event_exportButtonActionPerformed

    private void calculateButtonActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_calculateButtonActionPerformed
    {//GEN-HEADEREND:event_calculateButtonActionPerformed
        errorLabel.setText("");
        
        if (periapsisField.getText().trim().isEmpty() && apoapsisField.getText().trim().isEmpty())
            return;
        
        double periapsis = 0;
        
        try
        {
            periapsis = Double.parseDouble(periapsisField.getText().trim());
        }
        catch (NumberFormatException e)
        {
            errorLabel.setText("Error: invalid periapsis value");
            return;
        }

        if (pkmCheckbox.isSelected())
            periapsis *= 1000;
        else if (pMmCheckbox.isSelected())
            periapsis *= 1000000;
        else if (pGmCheckbox.isSelected())
            periapsis *= 1000000000;

        double apoapsis = 0;
        
        try
        {
            apoapsis = circularCheckbox.isSelected() ? periapsis : Double.parseDouble(apoapsisField.getText().trim());
        }
        catch (NumberFormatException e)
        {
            errorLabel.setText("Error: invalid apoapsis value");
            return;
        }

        if (!circularCheckbox.isSelected())
        {
            if (akmCheckbox.isSelected())
                apoapsis *= 1000;
            else if (aMmCheckbox.isSelected())
                apoapsis *= 1000000;
            else if (aGmCheckbox.isSelected())
                apoapsis *= 1000000000;
        }
        
        Body body = (Body) bodyComboBox.getSelectedItem();
        
        double soiMeters = body.soi * 1000;
        
        if (periapsis > soiMeters)
            errorLabel.setText("Warning: periapsis is outside body's SoI");
        else if (apoapsis > soiMeters)
            errorLabel.setText("Warning: apoapsis is outside body's SoI");
        else if (apoapsis < periapsis)
            errorLabel.setText("Warning: apoapsis is less than periapsis");
        
        double rp = periapsis + body.r;
        double ra = apoapsis + body.r;
        
        double sma = (rp + ra) / 2;
        double e = (ra - rp) / (ra + rp);
        double vp = Math.sqrt(((1 + e) * body.mu) / ((1 - e) * sma));
        double va = Math.sqrt(((1 - e) * body.mu) / ((1 + e) * sma));
        double T = 2 * Math.PI * Math.sqrt(sma * sma * sma / body.mu);
        
        double l = (2 * ra * rp) / (ra + rp); //semi-latus rectum
        double h = Math.sqrt(l * body.mu); //specific angular momentum

        double b = Math.sqrt(ra * rp); //semi-minor axis
        
        double darkness = (2 * sma * b / h) * (Math.asin(body.r / b) + (e * body.r / b));
        
        smaCraftLabel.setText(Utils.formatDistanceForLabel(sma));
        TCraftLabel.setText(Utils.formatTimeForLabelEarth(T));
        TKSPCraftLabel.setText(Utils.formatTimeForLabelKerbin(T));
        eCraftLabel.setText(Utils.DF_NO_DECIMAL_3.format(e));
        vpCraftLabel.setText(Utils.DF_ROUND_3.format(vp) + " m/s");
        vaCraftLabel.setText(Utils.DF_ROUND_3.format(va) + " m/s");
        darknessCraftLabel.setText(body == kerbol ? "-" : Utils.formatTimeForLabelEarth(darkness));
    }//GEN-LAST:event_calculateButtonActionPerformed

    private void periapsisFieldKeyReleased(java.awt.event.KeyEvent evt)//GEN-FIRST:event_periapsisFieldKeyReleased
    {//GEN-HEADEREND:event_periapsisFieldKeyReleased
        calculateButtonActionPerformed(null);
    }//GEN-LAST:event_periapsisFieldKeyReleased

    private void apoapsisFieldKeyReleased(java.awt.event.KeyEvent evt)//GEN-FIRST:event_apoapsisFieldKeyReleased
    {//GEN-HEADEREND:event_apoapsisFieldKeyReleased
        calculateButtonActionPerformed(null);
    }//GEN-LAST:event_apoapsisFieldKeyReleased

    private void pmCheckboxActionPerformed(java.awt.event.ActionEvent evt)//GEN-FIRST:event_pmCheckboxActionPerformed
    {//GEN-HEADEREND:event_pmCheckboxActionPerformed
        calculateButtonActionPerformed(null);
    }//GEN-LAST:event_pmCheckboxActionPerformed

    private void setBodyLabels(Body body)
    {
        if (body != kerbol)
        {
            smaBodyLabel.setText(Utils.formatDistanceForLabel(body.sma));
            rpBodyLabel.setText(Utils.formatDistanceForLabel(body.rp));
            raBodyLabel.setText(Utils.formatDistanceForLabel(body.ra));
            TBodyLabel.setText(Utils.formatTimeForLabelEarth(body.T));
            TKSPBodyLabel.setText(Utils.formatTimeForLabelKerbin(body.T));
            eBodyLabel.setText(Utils.DF_NO_DECIMAL_3.format(body.e));
            incBodyLabel.setText(Utils.DF_NO_DECIMAL_3.format(body.inc) + "°");
        }
        else
        {
            smaBodyLabel.setText("-");
            rpBodyLabel.setText("-");
            raBodyLabel.setText("-");
            TBodyLabel.setText("-");
            TKSPBodyLabel.setText("-");
            eBodyLabel.setText("-");
            incBodyLabel.setText("-");
        }
        MBodyLabel.setText(Utils.formatMass(body.M));
        gBodyLabel.setText("<html>" + Utils.DF_ROUND_3.format(body.g) + " m/s<sup>2</sup></html>");
        muBodyLabel.setText(Utils.formatGravitationalParameter(body.mu));
        rBodyLabel.setText(body.r + " m");
        maxElevationBodyLabel.setText(body.maxElevation + " m");
        soiBodyLabel.setText(Utils.DF_NO_DECIMAL_3.format(body.soi) + " km");
        flyingLowBodyLabel.setText(Utils.formatScienceAltitude(0, body.flyingLow));
        flyingHighBodyLabel.setText(Utils.formatScienceAltitude(body.flyingLow, body.atmosphereHeight));
        nearSpaceBodyLabel.setText(Utils.formatScienceAltitude(body.atmosphereHeight, body.nearSpace));
        outerSpaceBodyLabel.setText(Utils.formatScienceAltitude(body.nearSpace, body.soi));

        /* s²";
         s += "\n\tGravitational parameter (μ): " + mu + " m³/s²"; */
    }

    /**
     * @param args the command line arguments
     */
    public static void main(String args[])
    {
        /* Set the Nimbus look and feel */
        //<editor-fold defaultstate="collapsed" desc=" Look and feel setting code (optional) ">
        /* If Nimbus (introduced in Java SE 6) is not available, stay with the default look and feel.
         * For details see http://download.oracle.com/javase/tutorial/uiswing/lookandfeel/plaf.html 
         */
        try
        {
            for (javax.swing.UIManager.LookAndFeelInfo info : javax.swing.UIManager.getInstalledLookAndFeels())
            {
                if ("Nimbus".equals(info.getName()))
                {
                    javax.swing.UIManager.setLookAndFeel(info.getClassName());
                    break;
                }
            }
        }
        catch (ClassNotFoundException ex)
        {
            java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        catch (InstantiationException ex)
        {
            java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        catch (IllegalAccessException ex)
        {
            java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        catch (javax.swing.UnsupportedLookAndFeelException ex)
        {
            java.util.logging.Logger.getLogger(Main.class.getName()).log(java.util.logging.Level.SEVERE, null, ex);
        }
        //</editor-fold>

        /* Create and display the form */
        java.awt.EventQueue.invokeLater(new Runnable()
        {
            @Override
            public void run()
            {
                try
                {
                    new Main().setVisible(true);
                }
                catch (Exception e)
                {
                    e.printStackTrace();
                }
            }
        });
    }
    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JLabel MBodyLabel;
    private javax.swing.JLabel TBodyLabel;
    private javax.swing.JLabel TCraftLabel;
    private javax.swing.JLabel TKSPBodyLabel;
    private javax.swing.JLabel TKSPCraftLabel;
    private javax.swing.JRadioButton aGmCheckbox;
    private javax.swing.JRadioButton aMmCheckbox;
    private javax.swing.JRadioButton akmCheckbox;
    private javax.swing.JRadioButton amCheckbox;
    private javax.swing.JTextField apoapsisField;
    private javax.swing.ButtonGroup apoapsisUnits;
    private javax.swing.JComboBox bodyComboBox;
    private javax.swing.JPanel bodyVariablesPanel;
    private javax.swing.JButton calculateButton;
    private javax.swing.JCheckBox circularCheckbox;
    private javax.swing.JLabel darknessCraftLabel;
    private javax.swing.JLabel eBodyLabel;
    private javax.swing.JLabel eCraftLabel;
    private javax.swing.JLabel errorLabel;
    private javax.swing.JButton exportButton;
    private javax.swing.JLabel fillerLabel;
    private javax.swing.JLabel flyingHighBodyLabel;
    private javax.swing.JLabel flyingLowBodyLabel;
    private javax.swing.JPanel functionsPanel;
    private javax.swing.JLabel gBodyLabel;
    private javax.swing.JButton importButton;
    private javax.swing.JLabel incBodyLabel;
    private javax.swing.JTextField inclinationField;
    private javax.swing.JTextField inputField;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel10;
    private javax.swing.JLabel jLabel11;
    private javax.swing.JLabel jLabel12;
    private javax.swing.JLabel jLabel13;
    private javax.swing.JLabel jLabel14;
    private javax.swing.JLabel jLabel15;
    private javax.swing.JLabel jLabel16;
    private javax.swing.JLabel jLabel17;
    private javax.swing.JLabel jLabel18;
    private javax.swing.JLabel jLabel19;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JLabel jLabel20;
    private javax.swing.JLabel jLabel21;
    private javax.swing.JLabel jLabel22;
    private javax.swing.JLabel jLabel23;
    private javax.swing.JLabel jLabel24;
    private javax.swing.JLabel jLabel25;
    private javax.swing.JLabel jLabel26;
    private javax.swing.JLabel jLabel27;
    private javax.swing.JLabel jLabel28;
    private javax.swing.JLabel jLabel29;
    private javax.swing.JLabel jLabel3;
    private javax.swing.JLabel jLabel30;
    private javax.swing.JLabel jLabel4;
    private javax.swing.JLabel jLabel5;
    private javax.swing.JLabel jLabel6;
    private javax.swing.JLabel jLabel7;
    private javax.swing.JLabel jLabel8;
    private javax.swing.JLabel jLabel9;
    private javax.swing.JPanel jPanel1;
    private javax.swing.JPanel jPanel2;
    private javax.swing.JPanel jPanel3;
    private javax.swing.JScrollPane jScrollPane;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JScrollPane jScrollPane2;
    private javax.swing.JScrollPane jScrollPane4;
    private javax.swing.JTabbedPane jTabbedPane1;
    private javax.swing.JLabel maxElevationBodyLabel;
    private javax.swing.JLabel muBodyLabel;
    private javax.swing.JLabel nearSpaceBodyLabel;
    private javax.swing.JLabel outerSpaceBodyLabel;
    public javax.swing.JTextArea outputPane;
    private javax.swing.JRadioButton pGmCheckbox;
    private javax.swing.JRadioButton pMmCheckbox;
    private javax.swing.JTextField periapsisField;
    private javax.swing.ButtonGroup periapsisUnits;
    private javax.swing.JRadioButton pkmCheckbox;
    private javax.swing.JRadioButton pmCheckbox;
    private javax.swing.JLabel rBodyLabel;
    private javax.swing.JLabel raBodyLabel;
    private javax.swing.JLabel rpBodyLabel;
    private javax.swing.JLabel smaBodyLabel;
    private javax.swing.JLabel smaCraftLabel;
    private javax.swing.JLabel soiBodyLabel;
    private javax.swing.JPanel userVariablesPanel;
    private javax.swing.JLabel vaCraftLabel;
    private javax.swing.JLabel vpCraftLabel;
    // End of variables declaration//GEN-END:variables
}
